import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import javax.swing.JOptionPane;

/**
 * @author Claudio
 *
 */
public class Jogo implements IJogo {
	
	private Stack<Carta> deck;
	
	private Stack<Carta> descarte;
	
	private List<Jogador> jogadores;
	
	private Jogador jogadorAtual;
	
	private Jogador proximoJogador;
	
	private Jogador vencedor;
	
	private Sentido sentidoDoJogo;
	
	private Cor corAtual;
	
	public Jogo(){
		
		jogadores = new ArrayList<Jogador>();
		descarte = new Stack<Carta> ();
		
		iniciarNovoJogo();
	}
	
	/**
	 * @author Rafael
	 *
	 */
	@Override
	public void determinaOrdem() {
		Jogador primeiro = (Jogador) jogadores.get(0);	//variavel auxiliar recebe o primeiro jogador da lista 
		
		for (int i = 1; i < jogadores.size(); i++){	//la�o para pegar o jogador mais velho
			if (((Jogador) jogadores.get(i)).getIdade() < primeiro.getIdade() )
				primeiro = (Jogador) jogadores.get(i); 
		}
		
		setJogadorAtual((Jogador) jogadores.get(jogadores.indexOf(primeiro)));	//seta o jogador mais velho como jogador atual
		
		if (getSentidoDoJogo() == Sentido.HORARIO)
			if (jogadores.indexOf(primeiro)+1 < jogadores.size()-1)
				setProximoJogador((Jogador) jogadores.get(jogadores.indexOf(primeiro)+1));
			else
				setProximoJogador((Jogador) jogadores.get(0));
		else if (jogadores.indexOf(primeiro)-1 > 0)
				setProximoJogador((Jogador) jogadores.get(jogadores.indexOf(primeiro)-1));
			else
				setProximoJogador((Jogador) jogadores.get(jogadores.size() -1));
	}

	/**
	 * @author Rafael
	 *
	 */
	@Override
	public void distribuirMaos() {
		for(Jogador j: jogadores) {
			for(int i = 0; i < 7; i++) {
				j.getMao().add(deck.pop());
			}
		}
	}

	@Override
	public void checkCartaValida(Jogador jogador) {
		while (!jogador.validarMao(descarte.peek(),corAtual) || deck.isEmpty()) {
			jogador.getMao().add(deck.pop());
		}
	}

	@Override
	public void jogar(int indexCarta) {
		
		Carta carta = jogadorAtual.getMao().get(indexCarta); //Pega a carta selecionada pelo jogador.
		
		if(carta.isValida()) { // verifica se a carta é valida.
			corAtual = carta.getCor(); // define a cor atual do jogo de acordo com a carta selecionada.
			descarte.push(jogadorAtual.getMao().remove(indexCarta)); //remove a carta da mao do jogador e adiciona no descarte.
			
			Efeito e = carta.getEfeito(); 
			if (e != null){ // verifica se carta selecionada possui efeito, caso positivo, ativo o efeito da carta.
				
				if(e.equals(Efeito.SKIP)){ 
					nextJogador();	// Pula o proximo jogador
				}
				
				if(e.equals(Efeito.REVERSE)) { // Inverte o sentido do jogo.
					if (sentidoDoJogo.equals(Sentido.HORARIO)) { 
						sentidoDoJogo = Sentido.ANTIHORARIO; 
					} else { 
						sentidoDoJogo = Sentido.HORARIO;
					}
				}
				
				if(e.equals(Efeito.DRAW_2)) {  //O proximo jogador puxar duas carta e passa a vez.
					getProximoJogador().getMao().add(deck.pop()); 
					getProximoJogador().getMao().add(deck.pop());
					nextJogador();
				}
	
				if(e.equals(Efeito.WILD) || e.equals(Efeito.WILD_DRAW_4)){ // verifica se a carta é um curinga
					setCorAtual(new EscolherCor(null, true).getColor()); // exibe a janela de dialogo para que o jogador escola a cor do jogo.
					if(e.equals(Efeito.WILD_DRAW_4)) { // verifica se a carta é puxar 4.
						for (int i = 0; i < 4; i++){
							getProximoJogador().getMao().add(deck.pop());  // proximo jogador puxar 4 cartas e passa a vez.
						}
						nextJogador();
					}
				}
			}
			
			nextJogador(); // passa a vez para o proximo jogador.
			checkCartaValida(jogadorAtual); // verifica as cartas validas para o jogador que ira jogar.
			
			if(checkVencedor()) { // testa a existe um vencedor.
				JOptionPane.showMessageDialog(null, "Parabens, FIM DE JOGO");
				iniciarNovoJogo();
			}
		}
	}

	//atualiza o jogador atual e o pr�ximo jogador
	public void nextJogador(){
		if(sentidoDoJogo.equals(Sentido.HORARIO)) {
			int index = jogadores.indexOf(jogadorAtual);
			
			if(index == jogadores.size() -1) {
				jogadorAtual = jogadores.get(0);
				proximoJogador = jogadores.get(1);
			} else {
				jogadorAtual = jogadores.get(index+1);
				if(index + 2 == jogadores.size()) {
					proximoJogador = jogadores.get(0);
				} else {
					proximoJogador = jogadores.get(index + 2);
				}
			}
		} else {
			int index = jogadores.indexOf(jogadorAtual);
			
			if(index == 0) {
				jogadorAtual = jogadores.get(jogadores.size() - 1);
				proximoJogador = jogadores.get(jogadores.size() - 2);
			} else {
				jogadorAtual = jogadores.get(index - 1);
				if(index - 2 < 0) {
					proximoJogador = jogadores.get(jogadores.size() - 1);
				} else {
					proximoJogador = jogadores.get(index - 2);
				}
			}
		}
	}
	
	@Override
	public boolean checkVencedor() {
		for(Jogador j : jogadores) {
			if(j.getMao().isEmpty()) {
				vencedor = j;
				return true;
			}
		}
		return false;
	}

	@Override
	public void adicionarPontos() {
		
	}

	@Override
	public void iniciarNovoJogo() {
		deck = new Baralho().getDeck();
		sentidoDoJogo = Sentido.HORARIO;
		
		for(int i = 1; i <= 7; i++) {
			Jogador j = new Jogador();
			j.setNome("Jogador "+i);
			j.setIdade(i);
			jogadores.add(j);
		}
		
		determinaOrdem();
		
		distribuirMaos();
		
		do {
			descarte.push(deck.pop());
		} while (descarte.peek().getCor().equals(Cor.ESPECIAL));
		
		corAtual = descarte.peek().getCor();
		
		checkCartaValida(jogadorAtual);
		
	}
	
	/* GET AND SET */
	
	public Stack<Carta> getDeck() {
		return deck;
	}

	public void setDeck(Stack<Carta> deck) {
		this.deck = deck;
	}

	public Stack<Carta> getDescarte() {
		return descarte;
	}

	public void setDescarte(Stack<Carta> descarte) {
		this.descarte = descarte;
	}

	public List<Jogador> getJogadores() {
		return jogadores;
	}

	public void setJogadores(List<Jogador> jogadores) {
		this.jogadores = jogadores;
	}

	public Jogador getJogadorAtual() {
		return jogadorAtual;
	}

	public void setJogadorAtual(Jogador jogadorAtual) {
		this.jogadorAtual = jogadorAtual;
	}

	public Jogador getProximoJogador() {
		return proximoJogador;
	}

	public void setProximoJogador(Jogador proximoJogador) {
		this.proximoJogador = proximoJogador;
	}

	public Jogador getVencedor() {
		return vencedor;
	}

	public void setVencedor(Jogador vencedor) {
		this.vencedor = vencedor;
	}

	public Sentido getSentidoDoJogo() {
		return sentidoDoJogo;
	}

	public void setSentidoDoJogo(Sentido sentidoDoJogo) {
		this.sentidoDoJogo = sentidoDoJogo;
	}

	public Cor getCorAtual() {
		return corAtual;
	}

	public void setCorAtual(Cor corAtual) {
		this.corAtual = corAtual;
	}
	
	
}
